﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ContainerModel;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

namespace Artech.EnterLibExt.ExceptionHandling.Configuration
{
    public class FilterableHandlerData : ExceptionHandlerData
    {
        private const string FiltersPropertyName = "filters";
        private const string FilterTablesPropertyName = "filterTable";

        [ConfigurationProperty(FiltersPropertyName, IsRequired = false)]
        public NameTypeConfigurationElementCollection<ExceptionFilterData, CustomExceptionHandlerFilterData> Filters
        {
            get { return (NameTypeConfigurationElementCollection<ExceptionFilterData, CustomExceptionHandlerFilterData>)this[FiltersPropertyName]; }
            set { this[FiltersPropertyName] = value; }
        }

        [ConfigurationProperty(FilterTablesPropertyName)]
        public NamedElementCollection<ExceptionFilterTableEntryData> FilterTables
        {
            get { return (NamedElementCollection<ExceptionFilterTableEntryData>)this[FilterTablesPropertyName]; }
            set { this[FilterTablesPropertyName] = value; }
        }

        public override IEnumerable<TypeRegistration> GetRegistrations(string namePrefix)
        {
            foreach (var filterData in this.Filters)
            {
                foreach (var registration in filterData.GetRegistrations(namePrefix))
                {
                    yield return registration;
                }
            }
            var filterTableEntries = new List<ExceptionFilterTableEntry>();
            foreach (var filterTableData in this.FilterTables)
            {
                var filterRegistrationName = this.Filters.First(filer => filer.Name == filterTableData.Filter).BuildName(namePrefix);
                var exceptionHandlerNamePrefix = namePrefix + "." + filterTableData.Filter;
                var exceptionHandlerRegNames = new List<string>();

                foreach (var handlerData in filterTableData.ExceptionHandlers)
                {
                    exceptionHandlerRegNames.Add(handlerData.BuildName(exceptionHandlerNamePrefix));
                    foreach (var registration in handlerData.GetRegistrations(exceptionHandlerNamePrefix))
                    {
                        yield return registration;
                    }
                }
                filterTableEntries.Add(new ExceptionFilterTableEntry(filterRegistrationName, filterTableData.Priority, exceptionHandlerRegNames));

            }
            var filterTable = new ExceptionFilterTable(filterTableEntries);
            yield return new TypeRegistration<IExceptionHandler>(() => new FilterableHandler(filterTable))
            {
                Name = this.BuildName(namePrefix),
                Lifetime = TypeRegistrationLifetime.Transient
            };
        }
    }
}